package thunderbirdgtd.global;

import java.awt.Color;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.LinkedList;
import java.util.ListIterator;
import java.util.StringTokenizer;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import thunderbirdgtd.GTDParent;
import thunderbirdgtd.entities.Action;
import thunderbirdgtd.entities.Alarm;
import thunderbirdgtd.entities.Priority;
import thunderbirdgtd.entities.Project;
import thunderbirdgtd.entities.Tag;

public class XmlUtil {
	private SimpleDateFormat dateFormat = new SimpleDateFormat("dd-MMM-yyyy HH:mm:ss");
	
	public LinkedList<Project> allProjects = new LinkedList<Project>();
	public LinkedList<Tag> allTags = new LinkedList<Tag>();
	public LinkedList<Action> allActions = new LinkedList<Action>();
	public int childlessProjects = 0;



	public static void main(String args[]) {
		String projectsFile = "xml/projects.xml", actionsFile = "xml/actions.xml", tagsFile = "xml/tags.xml";
		XmlUtil xml = new XmlUtil();
		LinkedList<Project> projects = new LinkedList<Project>();
		LinkedList<Action> actions = new LinkedList<Action>();
		LinkedList<Tag> tags = new LinkedList<Tag>();

		Project project = new Project("project");
		Tag a = new Tag("taga");
		Tag b = new Tag("tagb");
		a.setColor(new Color(255, 255, 255));
		a.setTagDescription("Descri��o e tal da tag a ");
		b.setColor(new Color(25, 25, 25));
		b.setTagDescription("Descri��o e tal da tag b ");
		projects.add(project);
		Project project1 = new Project("project1");
		project.assignSubProject(project1);
		Project project2 = new Project("project2");
		project.assignSubProject(project2);
		Project project3 = new Project("project3");
		project2.assignSubProject(project3);
		projects.add(project1);
		projects.add(project2);
		projects.add(project3);
		Priority p = null;
		Priority p2 = null;
		LinkedList<Alarm> al = new LinkedList<Alarm>();
		Alarm e = new Alarm(new Date(), new Date(), 50);
		try {
			p = Priority.getHighPriorityInstance();
			p2 = Priority.getLowPriorityInstance();
			al.add(e);
			al.add(e);
			al.add(e);
			
		} catch (Exception e1) {
			e1.printStackTrace();
		}
		Action actiona = new Action("actiona");
		actiona.setParentProject(project);
		try {
			project.addTag(a);
			project.addTag(b);
			project.setPriority(p);
			project1.addTag(b);
			actiona.addTag(a);
			actiona.addTag(b);
			actiona.setPriority(p2);
			actiona.setAlarms(al);
		} catch (Exception ex) {
			ex.printStackTrace();
		}

		tags.add(a);
		tags.add(b);
		actions.add(actiona);
		xml.saveProjectsToXml(projects, projectsFile);
		xml.saveActionsToXML(actions, actionsFile);
		xml.saveTagsToXML(tags, tagsFile);
		try {
			DocumentBuilder parser = DocumentBuilderFactory.newInstance()
					.newDocumentBuilder();
			Document doc = parser.parse(new java.io.File(projectsFile));
			xml.readProjectsFromXML(doc);
			Document docProjects = doc;

			doc = parser.parse(new java.io.File(actionsFile));
			xml.readActionsFromXML(doc);
			Document docActions = doc;

			doc = parser.parse(new java.io.File(tagsFile));
			xml.readTagsFromXML(doc);

			XPath xpath = XPathFactory.newInstance().newXPath();
			xml.buildLogic(docProjects, docActions, xpath);
			xml.printAll();
		} catch (Exception ex) {
			ex.printStackTrace();
		}
	}

	public boolean saveProjectsToXml(LinkedList<Project> projects,
			String filename) {
		try {
			String[] types;
			String[] content;
			XmlWriter.writeHeaderWithoutDoctype(filename);
			XmlWriter.writeParentElement("gtd");

			ListIterator<Project> it = projects.listIterator();

			while (it.hasNext()) {
				Project project = (Project) it.next();
				types = new String[2];
				content = new String[2];
				types[0] = "name";
				content[0] = project.getName();
				types[1] = "id";
				content[1] = String.valueOf(project.getId());
				// project
				XmlWriter.writeParentElementWithAtts("project", types, content);

				writeTags(project.assignedTags);
				writeSubProjects(project.getSubProjects());

				if (project.getPriority() != null) {
					types = new String[3];
					content = new String[3];
					types[0] = "color";
					Color color = project.getPriority().getColor();
					content[0] = color.getRed() + "-" + color.getGreen() + "-"
							+ color.getBlue();
					types[1] = "level";
					content[1] = String.valueOf(project.getPriority()
							.getLevel());
					types[2] = "name";
					content[2] = project.getPriority().getName();
					XmlWriter.writeParentElementWithAtts("priority", types,
							content);
					XmlWriter.closeParentElement("priority");
				}

				XmlWriter.closeParentElement("project");
			}

			XmlWriter.closeParentElement("gtd");
			XmlWriter.closeFile();
			return true;
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
	}

	public void writeTags(LinkedList<Tag> tags) {
		String[] types;
		String[] content;
		ListIterator<Tag> itTag = tags.listIterator();

		while (itTag.hasNext()) {
			Tag tag = (Tag) itTag.next();
			types = new String[1];
			content = new String[1];
			types[0] = "id";
			content[0] = String.valueOf(tag.getTagId());

			XmlWriter.writeParentElementWithAtts("tag", types, content);
			XmlWriter.closeParentElement("tag");
		}
	}

	public void writeSubProjects(Project p) {
		String[] types;
		String[] content;

		types = new String[1];
		content = new String[1];
		types[0] = "id";
		content[0] = String.valueOf(p.getId());
		XmlWriter.writeParentElementWithAtts("project", types, content);
		XmlWriter.closeParentElement("tag");
	}

	public void writeSubProjects(LinkedList<Project> projects) {
		String[] types;
		String[] content;
		ListIterator<Project> itTag = projects.listIterator();

		while (itTag.hasNext()) {
			Project p = itTag.next();
			types = new String[1];
			content = new String[1];
			types[0] = "id";
			content[0] = String.valueOf(p.getId());
			XmlWriter.writeParentElementWithAtts("project", types, content);
			XmlWriter.closeParentElement("tag");
		}
	}

	public void readTagsFromXML(Document doc) throws XPathExpressionException {
		String expression = "/gtd/tag";

		XPath xpath = XPathFactory.newInstance().newXPath();

		NodeList tags = (NodeList) xpath.evaluate(expression, doc,
				XPathConstants.NODESET);
		// l� os projectos todos do ficheiro
		if (tags.getLength() != 0) {

			readAllTags(tags);
		}
	}

	public void readActionsFromXML(Document doc)
			throws XPathExpressionException {
		String expression = "/gtd/action";

		XPath xpath = XPathFactory.newInstance().newXPath();

		NodeList actions = (NodeList) xpath.evaluate(expression, doc,
				XPathConstants.NODESET);
		// l� os projectos todos do ficheiro
		if (actions.getLength() != 0) {

			readAllActions(actions);
		}
	}

	public void readAllActions(NodeList actions) {
		for (int i = 0, n = actions.getLength(); i < n; i++) {
			Node action = actions.item(i);
			Element p = (Element) action;
			String date = p.getAttribute("creationDate");
			Date creationDate;
			try {
				creationDate = dateFormat.parse(date);
			} catch (ParseException e) {
				e.printStackTrace();
				return;
			}
			Action a = new Action(p.getAttribute("name"), creationDate, Integer
					.parseInt(p.getAttribute("id")));
			String startdate = p.getAttribute("startDate");
			String enddate = p.getAttribute("endDate");
			try {
				a.startDate = dateFormat.parse(startdate);
				a.endDate = dateFormat.parse(enddate);
			} catch (ParseException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
			
			allActions.add(a);
		}
	}

	public void saveTagsToXML(LinkedList<Tag> tags, String tagsFile) {
		String[] types;
		String[] content;

		XmlWriter.writeHeaderWithoutDoctype(tagsFile);
		XmlWriter.writeParentElement("gtd");
		if (tags!=null){
		ListIterator<Tag> itTag = tags.listIterator();

		while (itTag.hasNext()) {
			Tag tag = (Tag) itTag.next();
			types = new String[3];
			content = new String[3];
			types[0] = "name";
			content[0] = tag.getTagName();
			types[1] = "id";
			content[1] = String.valueOf(tag.getTagId());
			types[2] = "color";
			content[2] = tag.getColor().getRed() + "-"
					+ tag.getColor().getGreen() + "-"
					+ tag.getColor().getBlue();
			XmlWriter.writeParentElementWithAtts("tag", types, content);
			XmlWriter.writeContent("desc", tag.getTagDescription());
			XmlWriter.closeParentElement("tag");
		}
		}
		XmlWriter.closeParentElement("gtd");
		XmlWriter.closeFile();
	}

	public void saveActionsToXML(LinkedList<Action> actions, String actionsFile) {
		String[] types;
		String[] content;

		XmlWriter.writeHeaderWithoutDoctype(actionsFile);
		XmlWriter.writeParentElement("gtd");
if (actions!=null){
		ListIterator<Action> itAction = actions.listIterator();

		while (itAction.hasNext()) {
			Action action = itAction.next();
			types = new String[5];
			content = new String[5];
			types[0] = "name";
			content[0] = action.getName();
			types[1] = "id";
			content[1] = String.valueOf(action.getId());
			types[2] = "creationDate";
			content[2] = dateFormat.format(action.getCreationDate());
			types[3] = "startDate";
			content[3] = dateFormat.format(action.startDate);
			types[4] = "endDate";
			content[4] = dateFormat.format(action.endDate);
			XmlWriter.writeParentElementWithAtts("action", types, content);
			writeTags(action.assignedTags);
			writeSubProjects(action.getParentProject());
			
			if (action.getPriority() != null) {
				types = new String[3];
				content = new String[3];
				types[0] = "color";
				Color color = action.getPriority().getColor();
				content[0] = color.getRed() + "-" + color.getGreen() + "-"
						+ color.getBlue();
				types[1] = "level";
				content[1] = String.valueOf(action.getPriority()
						.getLevel());
				types[2] = "name";
				content[2] = action.getPriority().getName();
				XmlWriter.writeParentElementWithAtts("priority", types,
						content);
				XmlWriter.closeParentElement("priority");
			}
			ListIterator<Alarm> ita = action.getAlarms().listIterator();
			while ( ita.hasNext()) {
				
				Alarm a = ita.next();
				
				types = new String[3];
				content = new String[3];
				types[0] = "creationdate";
				content[0] = dateFormat.format(a.getCreationDate());
				types[1] = "duedate";
				content[1] = dateFormat.format(a.getDueDate());
				types[2] = "seconds";
				content[2] = String.valueOf(a.getSecondsBefore());
				XmlWriter.writeParentElementWithAtts("alarm", types,
						content);
				XmlWriter.closeParentElement("alarm");
			}
			
			XmlWriter.closeParentElement("action");
		}
}
		XmlWriter.closeParentElement("gtd");
		XmlWriter.closeFile();
	}

	public void readProjectsFromXML(Document doc) throws Exception {
		String expression = "/gtd/project";

		XPath xpath = XPathFactory.newInstance().newXPath();

		NodeList projs = (NodeList) xpath.evaluate(expression, doc,
				XPathConstants.NODESET);
		// l� os projectos todos do ficheiro
		if (projs.getLength() != 0) {

			readAllProjects(projs);
		}
	}

	public void buildLogic(Document docProjects, Document docActions, XPath xpath) throws Exception {
		
		// Build projects
		ListIterator<Project> it = allProjects.listIterator();
		while (it.hasNext()) {
			// Get project and its tags
			Project tempProject = it.next();
			NodeList tags = (NodeList) xpath.evaluate("/gtd/project[@id = "
					+ tempProject.getId() + "]/tag", docProjects, XPathConstants.NODESET);
			for (int i = 0, n = tags.getLength(); i < n; i++) {
				Element tagEl = (Element) tags.item(i);
				String id = tagEl.getAttribute("id");
				tempProject.addTag(getTagByID(allTags, Integer.parseInt(id)));
			}

			// Get subprojects, if any
			NodeList subProjs = (NodeList) xpath.evaluate("/gtd/project[@id = "
					+ tempProject.getId() + "]/project", docProjects, XPathConstants.NODESET);
			for (int i = 0, n = subProjs.getLength(); i < n; i++) {
				Element tagEl = (Element) subProjs.item(i);
				String id = tagEl.getAttribute("id");
				Project subP = getProjectByID(allProjects, Integer.parseInt(id));
				subP.setParentProject(tempProject);
				tempProject.assignSubProject(subP);
			}
			
			// Check if it has no parent Project
			if(!tempProject.isSubProject()) {
				childlessProjects++;
			}

			// Get project priority
			Node prior = (Node) xpath.evaluate("/gtd/project[@id = "
					+ tempProject.getId() + "]/priority", docProjects, XPathConstants.NODE);
			if (prior != null) {

				Element tagEl = (Element) prior;
				String colorString = tagEl.getAttribute("color");
				StringTokenizer tok = new StringTokenizer(colorString, "-");
				Color color = new Color(Integer.parseInt(tok.nextToken()),
						Integer.parseInt(tok.nextToken()), Integer.parseInt(tok
								.nextToken()));
				String level = tagEl.getAttribute("level");
				String name = tagEl.getAttribute("name");
				Project subP = getProjectByID(allProjects, tempProject.getId());

				Priority priority = new Priority(Integer.parseInt(level), name,
						color);
				subP.setPriority(priority);
			}

		}

		
		// Build actions
		ListIterator<Action> itAction = allActions.listIterator();
		while (itAction.hasNext()) {
			// Get action and its tags
			Action tempAction = itAction.next();
			NodeList tags = (NodeList) xpath.evaluate("/gtd/action[@id = "
					+ tempAction.getId() + "]/tag", docActions, XPathConstants.NODESET);
			for (int i = 0, n = tags.getLength(); i < n; i++) {
				Element tagEl = (Element) tags.item(i);
				String id = tagEl.getAttribute("id");
				tempAction.addTag(getTagByID(allTags, Integer.parseInt(id)));
			}

			NodeList subProjs = (NodeList) xpath.evaluate("/gtd/action[@id = "
					+ tempAction.getId() + "]/project", docActions, XPathConstants.NODESET);
			for (int i = 0, n = subProjs.getLength(); i < n; i++) {
				Element tagEl = (Element) subProjs.item(i);
				String id = tagEl.getAttribute("id");
				
				Project parentProject = getProjectByID(allProjects, Integer.parseInt(id));
				tempAction.setParentProject(parentProject);
				parentProject.addAction(tempAction);
			}
			

			// Get project alarms
			NodeList alarms = (NodeList) xpath.evaluate("/gtd/action[@id = "
					+ tempAction.getId() + "]/alarm", docActions, XPathConstants.NODESET);
			for (int i = 0, n = alarms.getLength(); i < n; i++) {
				Element alarmEl = (Element) alarms.item(i);
				Date creationdate = dateFormat.parse(alarmEl.getAttribute("creationdate"));
				Date duedate = dateFormat.parse(alarmEl.getAttribute("duedate"));
				long seconds = Long.parseLong((alarmEl.getAttribute("seconds")));
				Alarm alarm = new Alarm(creationdate, duedate, seconds);
				getActionByID(allActions, tempAction.getId()).addAlarmAction(alarm);
			}
		
			
			// Get project priority
			Node prior = (Node) xpath.evaluate("/gtd/action[@id = "
					+ tempAction.getId() + "]/priority", docActions, XPathConstants.NODE);
			if (prior != null) {

				Element priorityElement = (Element) prior;
				String colorString = priorityElement.getAttribute("color");
				StringTokenizer tok = new StringTokenizer(colorString, "-");
				Color color = new Color(Integer.parseInt(tok.nextToken()),
						Integer.parseInt(tok.nextToken()), Integer.parseInt(tok
								.nextToken()));
				String level = priorityElement.getAttribute("level");
				String name = priorityElement.getAttribute("name");
				
				//Project subP = getProjectByID(allProjects, a.getId());

				Priority priority = new Priority(Integer.parseInt(level), name,
						color);
				//subP.setPriority(priority);
				getActionByID(allActions, tempAction.getId()).setPriority(priority);
			}
		}
	}

	public void printAll() {

		ListIterator<Project> itP = allProjects.listIterator();
		while (itP.hasNext()) {
			Project p = itP.next();
			System.out.println(p.toString());
			ListIterator<Tag> it = p.assignedTags.listIterator();
			while (it.hasNext()) {
				Tag t = it.next();
				System.out.println("\t" + t);
			}
			ListIterator<Project> itSub = p.getSubProjects().listIterator();
			while (itSub.hasNext()) {
				Project sub = itSub.next();
				System.out.println("\t\t" + sub);
			}
		}

		System.out.println("\n");

		ListIterator<Action> itA = allActions.listIterator();
		while (itA.hasNext()) {
			Action a = itA.next();
			System.out.println(a.toString());
			ListIterator<Tag> it = a.assignedTags.listIterator();
			while (it.hasNext()) {
				Tag t = it.next();
				System.out.println("\t" + t);
			}

			System.out.println("\t\t" + a.getParentProject());
		}
	}

	public void readAllTags(NodeList tags) {
		for (int i = 0, n = tags.getLength(); i < n; i++) {
			if (tags.item(i).getNodeType() == Node.ELEMENT_NODE) {
				Element tagEl = (Element) tags.item(i);
				NodeList fstNmElmntLst = tagEl.getElementsByTagName("desc");
				String id = tagEl.getAttribute("id");
				String name = tagEl.getAttribute("name");
				String colorString = tagEl.getAttribute("color");
				StringTokenizer tok = new StringTokenizer(colorString, "-");
				Color color = new Color(Integer.parseInt(tok.nextToken()),
						Integer.parseInt(tok.nextToken()), Integer.parseInt(tok
								.nextToken()));
				Element fstNmElmnt = (Element) fstNmElmntLst.item(0);
				NodeList fstNm = fstNmElmnt.getChildNodes();
				String desc = ((Node) fstNm.item(0)).getNodeValue();
				Tag newTag = new Tag(name, color, Integer.parseInt(id));
				newTag.setTagDescription(desc);
				// se ainda n�o existir, guardar na linkedList
				if (getTagByID(allTags, Integer.parseInt(id)) == null)
					allTags.add(newTag);
			}
		}
	}

	public void readAllProjects(NodeList projs) {
		for (int i = 0, n = projs.getLength(); i < n; i++) {
			Node project = projs.item(i);
			Element p = (Element) project;
			Project proj = new Project(p.getAttribute("name"), Integer
					.parseInt(p.getAttribute("id")));
			allProjects.add(proj);
		}
	}

	public Project getProjectByID(LinkedList<Project> projects, int id) {
		ListIterator<Project> it = projects.listIterator();
		while (it.hasNext()) {
			Project p = it.next();
			if (p.getId() == id)
				return p;
		}
		return null;
	}

	public Tag getTagByID(LinkedList<Tag> tags, int id) {
		ListIterator<Tag> it = tags.listIterator();
		while (it.hasNext()) {
			Tag t = it.next();
			if (t.getTagId() == id)
				return t;
		}
		return null;
	}
	
	public Action getActionByID(LinkedList<Action> actions, int id) {
		ListIterator<Action> it = actions.listIterator();
		while (it.hasNext()) {
			Action p = it.next();
			if (p.getId() == id)
				return p;
		}
		return null;
	}
	
	public static void saveAll(String path, GTDParent gtd) throws Exception{
	      String projectsFile = "projects.xml";
	        String actionsFile = "actions.xml";
	        String tagsFile = "tags.xml";
	        
	        XmlUtil xml = new XmlUtil();
	       
	        xml.saveProjectsToXml(gtd.projects, path + "/" + projectsFile);           
	        xml.saveActionsToXML(gtd.actions, path + "/" + actionsFile);
	        xml.saveTagsToXML(gtd.tags, path + "/" + tagsFile);
	}
	
	public static void openAll(String path, GTDParent gtd) throws Exception {
        String projectsFile = "projects.xml";
        String actionsFile = "actions.xml";
        String tagsFile = "tags.xml";
        
        XmlUtil xml = new XmlUtil();
        DocumentBuilder parser = DocumentBuilderFactory.newInstance().newDocumentBuilder();
        
        Document docProjects = parser.parse(new java.io.File(path +"/" + projectsFile));
        xml.readProjectsFromXML(docProjects);
        
        Document docActions;
        docActions = parser.parse(new java.io.File(path + "/" +actionsFile));
        xml.readActionsFromXML(docActions);

        Document docTags;
        docTags = parser.parse(new java.io.File(path + "/" +tagsFile));
        xml.readTagsFromXML(docTags);

        XPath xpath = XPathFactory.newInstance().newXPath();
        xml.buildLogic(docProjects, docActions, xpath);
        
        gtd.setNParentProjects(xml.childlessProjects);
        gtd.projects = xml.allProjects;
        gtd.actions = xml.allActions;
        gtd.tags = xml.allTags;
	}
	
	
}
